// Copyright (c) Microsoft Corporation. All rights reserved.

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace Microsoft.TeamFoundation.Migration.Toolkit.Wit
{
    /// <summary>
    /// Internal change list; represents a collection of atomic updates to a work item.
    /// </summary>
    class InternalChangeList
    {
        private SyncProcess m_sharedData;                   // Shared data object
        private Pair<FullId> m_ids;                         // Ids of source and target items
        private int m_sourceRevs;                           // Number of revisions on the source side
        private int m_targetRevs;                           // Number of revisions on the target side
        private Side m_targetSide;                          // Side being updated by the change list
        private Queue<IWorkItemUpdate> m_updates;           // All updates to the work item
        private Watermark m_target;                         // Target revison
        private RevisionMapper m_mapper;                    // Revision mapper

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="targetSide">Side being updated</param>
        /// <param name="ids">Source/target ids</param>
        /// <param name="targetId">Id of the target work item (existing items only)</param>
        /// <param name="changes">Underlying changes</param>
        /// <param name="mapper">Revision mapper</param>
        public InternalChangeList(
            Side targetSide,
            Pair<FullId> ids,
            IWorkItemUpdatePackage changes,
            RevisionMapper mapper)
        {
            m_sharedData = mapper.SharedData;
            m_targetSide = targetSide;
            m_ids = ids;
            m_sourceRevs = changes.Revisions.Count;
            m_updates = new Queue<IWorkItemUpdate>(changes.Translate());
            m_mapper = mapper;

            m_targetRevs = m_updates.Count;
        }

        /// <summary>
        /// Tells whether the change list contains no more 
        /// </summary>
        public bool IsEmpty { get { return m_updates.Count == 0; } }

        /// <summary>
        /// Gets the next unsubmitted update statement.
        /// </summary>
        /// <returns>Update statement or null if there're no more statements</returns>
        public IWorkItemUpdate GetNextUpdate()
        {
            if (m_updates.Count > 0)
            {
                IWorkItemUpdate u = m_updates.Dequeue();
                if (m_target != null)
                {
                    u.SetTarget(m_target);
                }

                return u;
            }
            return null;
        }

        /// <summary>
        /// Updates watermark for pending update statements in the list.
        /// </summary>
        /// <param name="sourceRev">Number of source revision</param>
        /// <param name="watermark">New watermark</param>
        public void UpdateWatermark(
            int sourceRev,
            Watermark watermark)
        {
            // Update internal database
            if (sourceRev != -1)
            {
                m_mapper.Update(m_targetSide, sourceRev, watermark);
            }

            m_target = watermark;

            if (m_ids[m_targetSide] == null)
            {
                m_ids[m_targetSide] = new FullId(
                    m_sharedData.Stores[m_targetSide], watermark.Id);
            }
        }

        /// <summary>
        /// Returns id of the source work item.
        /// </summary>
        public FullId SourceId { get { return m_ids[!m_targetSide]; } }

        /// <summary>
        /// Returns id of the target work item.
        /// </summary>
        public FullId TargetId { get { return m_ids[m_targetSide]; } }

        /// <summary>
        /// Returns number of revisions on the source side.
        /// </summary>
        public int SourceRevisions { get { return m_sourceRevs; } }

        /// <summary>
        /// Returns number of revisions that should be created on the target side.
        /// </summary>
        public int TargetRevisions { get { return m_targetRevs; } }
    }
}
